package tictactoe.gameplay;

import tictactoe.types.*;

/**
 *
 * @author Ryan Falls
 */
public class HardCPUPlayer extends EasyCPUPlayer
{

    public HardCPUPlayer(CellState symbol)
    {
	super(symbol);
    }

    /**
     *
     * @param classStates
     * @return
     */
    @Override
    public int MakeMove(CellState[] cellStates)
    {
	int move = -1;
	CellState opponentSymbol = ((playerSymbol == CellState.X) ? CellState.O : CellState.X);

	//If Player has two in a row, column, or diagonal, make winning move.
	move = canWin(playerSymbol, cellStates);
	if(move != -1)
	{
	    return move;
	}

	//Else If opponent has two in a row, column, or diagonal, make blocking move.
	move = canWin(opponentSymbol, cellStates);
	if(move != -1)
	{
	    return move;
	}

	//Else make a random move (uses the super class's algorithm)
	return makeArbitraryMove(cellStates);
    }

    /**
     * Checks to see if the player indicated by symbol has a winning move in cellStates.
     * @param symbol The player to search for a winning move
     * @param cellStates
     * @return The place to move to win, or -1 if no winning move.
     */
    /*Note: TicTacToe board:
     * [0|1|2]
     * [3|4|5]
     * [6|7|8]
     */
    private int canWin(CellState symbol, CellState[] cellStates)
    {
	int move;

	if(symbol == CellState.NONE)
	{
	    //TODO: Throw exception
	}

	for(int i = 0; i < 3; i++)
	{
	    //Check rows
	    move = checkSpotsForWin(3 * i, 3 * i + 1, 3 * i + 2, symbol, cellStates);
	    if(move != -1)
	    {
		return (3 * i + move);
	    }
	    //Check columns
	    move = checkSpotsForWin(i, i + 3, i + 6, symbol, cellStates);
	    if(move != -1)
	    {
		return (3 * move + i);
	    }
	}
	//Check diagonals
	move = checkSpotsForWin(0, 4, 8, symbol, cellStates);
	if(move != -1)
	{
	    return (move * 4);
	}
	move = checkSpotsForWin(2, 4, 6, symbol, cellStates);
	if(move != -1)
	{
	    return ((move + 1) * 2);
	}

	return -1;
    }

    /**
     * Checks the three locations (spot0, spot1, & spot2), if a move can be made in any
     * of the three spots to win.
     * @param spot0 First spot to check
     * @param spot1 Second spot to check
     * @param spot2 Third spot to check
     * @param symbol Target symbol
     * @param cellStates
     * @return Returns 0-2 to indicate that spot is a winning spot, -1 if none.
     */
    private int checkSpotsForWin(int spot0, int spot1, int spot2, CellState symbol, CellState[] cellStates)
    {
	//Check if first spot is winning move
	if((cellStates[spot0] == CellState.NONE) && (cellStates[spot1] == symbol) && (cellStates[spot2] == symbol))
	{
	    return 0;
	}

	//Check if second spot is winning move
	if((cellStates[spot1] == CellState.NONE) && (cellStates[spot0] == symbol) && (cellStates[spot2] == symbol))
	{
	    return 1;
	}

	//Check if third spot is winning move
	if((cellStates[spot2] == CellState.NONE) && (cellStates[spot0] == symbol) && (cellStates[spot1] == symbol))
	{
	    return 2;
	}

	return -1;
    }
}
